﻿/**
 * @file lj_ringbuffer.h
 * @author Liu Bingyi (cecillearfa@163.com)
 * @brief
 * @version 0.2
 * @date 2023-08-21
 *
 * @copyright Copyright (c) 2023 Liu Bingyi
 *  lj-ringbuffer is licensed under Mulan PubL v2.
 *  You can use this software according to the terms and conditions of the Mulan PubL v2.
 *  You may obtain a copy of Mulan PubL v2 at:
 *           http://license.coscl.org.cn/MulanPubL-2.0
 *  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 *  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 *  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *  See the Mulan PubL v2 for more details.
 *
 *
 *                      Mulan Public License，Version 2
 *
 *  Mulan Public License，Version 2 (Mulan PubL v2)
 *
 *  May 2021 http://license.coscl.org.cn/MulanPubL-2.0
 *
 */
#ifndef _LJ_RINGBUFFER_H_
#define _LJ_RINGBUFFER_H_

#include <pthread.h>
#include <stddef.h>
#include <stdint.h>

#include "ljdef.h"

#define LJ_RINGBUFFER_MAX 10000 // 缓冲区的限制最大长度，目前没有任何作用

#define BUFFER_TYPE struct data_buf // 对缓冲区存储的实际类型进行抽象，方便后续的修改

#define BUFFER_SIZEOF(LENGTH) (sizeof(BUFFER_TYPE) * LENGTH) // 求缓冲区实际类型的所占的字节

struct lj_ringbuffer {
    BUFFER_TYPE* buffer;
    size_t buffer_size;
    size_t rb_r_index;
    uint16_t rb_r_mirror : 1;
    size_t rb_w_index;
    uint16_t rb_w_mirror : 1;
};
typedef struct lj_ringbuffer lj_ringbuffer_t; // 环形缓冲区的便利类型。

struct lj_ringbuffer_sync {
    volatile BUFFER_TYPE* buffer;
    volatile size_t buffer_size;
    volatile size_t rb_r_index;
    volatile uint16_t rb_r_mirror : 1;
    volatile size_t rb_w_index;
    volatile uint16_t rb_w_mirror : 1;
    pthread_mutex_t rbs_lock;
};

typedef struct lj_ringbuffer_sync lj_ringbuffer_sync_t; // 线程安全环形缓冲区的便利类型。

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief 初始化环形缓冲
 *
 * @param rb 指向需要初始化的环形缓冲区结构的指针
 * @param pool 指向环形缓冲区内存储实际存储数据的内存块首地址的指针
 * @param pool_size 实际存储内存的容量
 * @return int 初始化成功返回0
 */
int lj_ring_buffer_init(lj_ringbuffer_t* rb, BUFFER_TYPE* pool, size_t pool_size);

/**
 * @brief 向缓冲区内写入length个数据，目前执行的策略是如果缓冲区内剩余的空间足够，就会成功写入；如果缓冲区不够就会放弃所有的写入并返回
 *
 * @param rb 需要推入的环形缓冲区
 * @param src 数据源
 * @param length 数据个数
 * @return size_t 实际写入的个数，如果成功写入返回length。如果没有写入返回0。
 */
size_t lj_ring_buffer_push(lj_ringbuffer_t* rb, const BUFFER_TYPE* src, size_t length);

/**
 * @brief 从缓冲区内读出length给数据，并且存入dest指针指向的内存。目前如果缓冲区内保存的数据足够就会成功读出，否则会直接放弃读取，并且返回零
 *
 * @param rb 需要读取数据的环形缓冲区
 * @param dest 存储数据的内存首地址
 * @param length 需要读取的数据个数
 * @return size_t 实际读出的数据个数，如果成功读取返回length，如果没有读取任何数据返回0.
 */
size_t lj_ring_buffer_pull(lj_ringbuffer_t* rb, BUFFER_TYPE* dest, size_t length);

int lj_ring_buffer_sync_init(lj_ringbuffer_sync_t* rb_sync, BUFFER_TYPE* pool, size_t pool_size);

size_t lj_ring_buffer_sync_push(lj_ringbuffer_sync_t* rb_sync, const BUFFER_TYPE* src, size_t length);
size_t lj_ring_buffer_sync_pull(lj_ringbuffer_sync_t* rb_sync, BUFFER_TYPE* dest, size_t length);
size_t lj_ring_buffer_sync_trypush(lj_ringbuffer_sync_t* rb_sync, const BUFFER_TYPE* src, size_t length);
size_t lj_ring_buffer_sync_trypull(lj_ringbuffer_sync_t* rb_sync, BUFFER_TYPE* dest, size_t length);

#ifdef __cplusplus
}
#endif

#endif